from django.views.generic import View
from django.http import JsonResponse
import json
import traceback
from user.utils.login import get_user_by_token
from user.models import Empower
from pms import settings


def get_pids_by_rid(rid):
    return [int(x['pid']) for x in Empower.objects.filter(rid=rid).order_by('pid_id').values('pid')]


class BadTokenError(Exception):
    pass


class PermissionDeny(Exception):
    pass


class ParameterLost(Exception):
    pass


class RequestBody(dict):
    def __init__(self, body):
        super().__init__(body)

    def __getitem__(self, item):
        try:
            return super().__getitem__(item)
        except KeyError:
            raise ParameterLost

    def get(self, key, default=None):
        try:
            return super().get(key, default)
        except KeyError:
            raise ParameterLost


class PostFormula(View):

    require_permissions = []

    def __init__(self, **kwargs):
        View.__init__(self, **kwargs)
        self.req = None
        self.req_body = None
        self.token = None
        self.user = None

    def success_respond(self, body=None):
        return JsonResponse({
            'code': 'OK',
            'message': '',
            'body': body if body is not None else {}
        })

    def failed_respond(self, code, message='', body=None):
        return JsonResponse({
            'code': code,
            'message': message,
            'body': body if body is not None else {}
        })

    def check_permissions(self, user):
        pids = get_pids_by_rid(user.rid)  # Permissions that user has.
        # print(self.require_permissions, pids)
        # All permission.
        if 1 in pids:
            return None
        for pid in self.require_permissions:
            if pid not in pids:
                raise PermissionDeny

    def has_permissions(self, permissions):
        """ 判断此用户是否有列表中的权限 """
        pids = get_pids_by_rid(self.user.rid)
        if 1 in pids:  # User has all permission.
            return True
        for pid in permissions:
            if pid not in pids:
                return False
        return True

    def has_one_of_permissions(self, permissions):
        """ 判断此用户是否有列表中的至少一种权限 """
        pids = get_pids_by_rid(self.user.rid)
        if 1 in pids:  # User has all permission.
            return True
        for pid in permissions:
            if pid in pids:
                return True
        return False

    def assert_permissions(self, permissions):
        """ 断言此用户有列表中的权限，否则自动产生 PermissionDeny """
        if not self.has_permissions(permissions):
            raise PermissionDeny

    def assert_one_of_permissions(self, permissions):
        """ 断言此用户有列表中的至少一种权限，否则自动产生 PermissionDeny """
        if not self.has_one_of_permissions(permissions):
            raise PermissionDeny

    def handle(self, req):
        """ 请求处理函数，各接口继承此类并覆盖本方法 """
        pass

    def pre_handle(self, request):
        """ 请求处理函数执行前的准备 """
        self.req = json.loads(request.body.decode('utf-8'))
        self.req_body = RequestBody(self.req['body'])
        self.token = self.req['token']
        if request.path not in ['/user/login']:
            try:
                self.user = get_user_by_token(self.token)
            except Exception:
                raise BadTokenError
            self.check_permissions(self.user)

    def post(self, request):
        try:
            self.pre_handle(request)
            return self.handle(self.req_body)
        except BadTokenError:
            return self.failed_respond('BAD_TOKEN', '无效 token ，客户端没有登录态')
        except PermissionDeny:
            return self.failed_respond('NO_PERMISSION', '用户没有权限进行此操作')
        except ParameterLost:
            return self.failed_respond('PARAMETER_LOST', '请求体缺失参数')
        except Exception as e:
            if settings.DEBUG:
                traceback.print_exception(e)
            return self.failed_respond('UNKNOWN', 'Unknown Error')
